
#include <BPainter>

#include "member_BStatusBar.h"
#include "member_BWidget.h"
#include "member_BStyle.h"
#include "member_BObject.h"

using namespace BWE;

#define member					(*(member_BStatusBar*)_ptr)
#define member_allocate()		_ptr = new member_BStatusBar(this)
#define member_release()		delete (member_BStatusBar*)_ptr

BStatusBar::BStatusBar(BWidget* parent) : BWidget(parent)
{
	member_allocate();
}
BStatusBar::BStatusBar(Form form, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setForm(form);
}
BStatusBar::BStatusBar(const BString& text, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setText(text);
}
BStatusBar::BStatusBar(BImage* image, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setImage(image);
}
BStatusBar::BStatusBar(BImage* image, const BString& text, BWidget* parent) : BWidget(parent)
{
	member_allocate();
	setImage(image);
	setText(text);
}
BStatusBar::~BStatusBar()
{
	member_release();
}

void BStatusBar::setForm(Form form)
{
	if (member.ia_form != form)
	{
		member.ia_form = form;
		member.dirty = true;
		this->fresh();
	}
}
Form BStatusBar::form() const
{
	return member.ia_form;
}

void BStatusBar::setAlign(Align align)
{
	if (member.ia_align != align)
	{
		member.ia_align = align;
		member.dirty = true;
		this->emit(Signal_AlignChanged, align);
		this->fresh();
	}
}
Align BStatusBar::align() const
{
	return member.ia_align;
}

void BStatusBar::setImage(BImage* image)
{
	if (member.image != image)
	{
		member.image = image;
		member.dirty = true;
		this->fresh();
		this->emit(Signal_ImageChanged, member.image);
	}
}
BImage* BStatusBar::image()
{
	return member.image;
}
const BImage* BStatusBar::image() const
{
	return member.image;
}

void BStatusBar::setImageSize(const BSize& imageSize)
{
	if (member.imageSize != imageSize)
	{
		member.imageSize = imageSize;
		member.dirty = true;
		this->adjust();
	}
}
const BSize& BStatusBar::imageSize() const
{
	return member.imageSize;
}

void BStatusBar::setText(const BString& text)
{
	if (member.text != text)
	{
		member.text = text;
		member.dirty = true;
		this->fresh();
		object_member(this)->check_emit(Signal_TextChanged, member.text);
	}
}
const BString& BStatusBar::text() const
{
	return member.text;
}

void BStatusBar::setTextFormat(BTextFormat* textFormat)
{
	if (member.block.format() != textFormat)
	{
		member.block.setFormat(textFormat);
		member.block.dirty = true;
		member.dirty = true;
		this->emit(Signal_FormatChanged, textFormat);
		this->fresh();
	}
}
const BTextFormat* BStatusBar::textFormat() const
{
	return member.block.format();
}
BTextFormat* BStatusBar::textFormat()
{
	return member.block.format();
}

void BStatusBar::setTimeout(BReal timeout)
{
	if (member.timeout != timeout)
	{
		member.timeout = timeout;
		member.lastTick = bTime();
		member.alpha = 1;
		this->emit(Signal_TimeChanged, timeout);
		this->fresh();
	}
}
BReal BStatusBar::timeout() const
{
	return member.timeout;
}

void BStatusBar::setFadeTime(BReal fadeTime)
{
	if (member.fadeTime != fadeTime)
	{
		member.fadeTime = fadeTime;
		member.lastTick = bTime();
		member.alpha = 1;
		this->fresh();
	}
}
BReal BStatusBar::fadeTime() const
{
	return member.fadeTime;
}

void BStatusBar::showMessage(const BString& message, BReal timeout)
{
	setText(message);
	setTimeout(timeout);
}
void BStatusBar::showMessage(BImage* image, const BString& message, BReal timeout)
{
	setImage(image);
	setText(message);
	setTimeout(timeout);
}

BSize BStatusBar::sizeHint() const
{
	if (member.dirty)
	{
		member.freshRects();
		member.dirty = false;
	}
	const BFont* font = this->realFont();
	BSize contentSize = member.ia_iconSize;
	contentSize.width() += font->size() * 10;
	if (contentSize.height() < font->size())
		contentSize.height() = font->size();
	return BWidget::preferSize(contentSize);
}

void BStatusBar::resizeEvent(const BEvent& event)
{
	member.dirty = true;
	BWidget::resizeEvent(event);
}
void BStatusBar::updateEvent(const BEvent& event)
{
	if (member.timeout > 0)
	{
		BReal diff = event.time() - member.lastTick;
		member.timeout -= diff;
		if (member.timeout < 0)
		{
			member.timeout = 0;
			member.alpha = 1.0f;
			emit(Signal_TimeOut);
		}
		member.lastTick = event.time();
		this->fresh();
	}
	if (member.timeout == 0 && member.fadeTime > 0)
	{
		BReal alpha = 0;
		BReal diff = bTime() - member.lastTick;
		if (diff < member.fadeTime)
		{
			alpha = (member.fadeTime - diff) / member.fadeTime;
		}
		if (member.alpha != alpha)
		{
			member.alpha = alpha;
			this->fresh();
		}
	}
	BWidget::updateEvent(event);
}

void BStatusBar::styleEvent(const BEvent& event)
{
	BWidget::styleEvent(event);
	const BStyle* style = event.value();
	style_member(style)->assign(Value_Text, member.text);
	style_member(style)->assign(Value_Color, member.color);
	style_member(style)->assign(Value_Image, member.image);
	style_member(style)->assign(Value_Image_Size, member.imageSize);
	style_member(style)->assign(Value_Align, member.ia_align);
	style_member(style)->assign(Value_Spacing, member.ia_spacing);
	member.dirty = true;
}
void BStatusBar::freshEvent(const BEvent& event)
{
	BWidget::freshEvent(event);
	if (member.dirty)
	{
		member.freshRects();
		member.dirty = false;
	}
}
void BStatusBar::paintEvent(const BEvent& event)
{
	BPainter painter(this);
	painter.drawBackground();
	painter.drawPerch();

	State state = painter.state();
	if (member.timeout != 0)
	{
		if (member.image)
		{
			painter.setColor(member.color);
			painter.drawImage(member.ia_iconRect, member.image);
		}
		BColor textColor = painter.color(Color_Text, state) * member.alpha;
		if (painter.setColor(textColor))
		{
			member.block.paint(painter);
		}
	}
	else if (member.fadeTime > 0 && member.alpha > 0)
	{
		if (member.image)
		{
			painter.setColor(member.color * member.alpha);
			painter.drawImage(member.ia_iconRect, member.image);
		}
		BColor textColor = painter.color(Color_Text, state) * member.alpha;
		if (painter.setColor(textColor))
		{
			member.block.paint(painter);
		}
	}

	painter.drawMargin();
	painter.drawBorder();
}
